# ##############################################################################
# cmake/nuttx_add_makefile.cmake
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements.  See the NOTICE file distributed with this work for
# additional information regarding copyright ownership.  The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License.  You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################

include(ProcessorCount)
ProcessorCount(N)
if(NOT N EQUAL 0)
  set(MAKE_PARALLELISM -j${N} GLOBAL)
endif()

add_custom_target(
  mkdeps
  COMMAND cmake -B ${CMAKE_BINARY_DIR}/bin -S ${NUTTX_DIR}/tools && cmake
          --build ${CMAKE_BINARY_DIR}/bin --target mkdeps
  SOURCES ${NUTTX_DIR}/tools/mkdeps.c)

add_custom_target(
  incdir
  COMMAND cmake -B ${CMAKE_BINARY_DIR}/bin -S ${NUTTX_DIR}/tools && cmake
          --build ${CMAKE_BINARY_DIR}/bin --target incdir
  SOURCES ${NUTTX_DIR}/tools/incdir.c
  DEPENDS mkdeps)

function(generate_common_defs)
  get_property(
    EXTRA_INCLUDE_DIRS
    TARGET nuttx
    PROPERTY NUTTX_INCLUDE_DIRECTORIES)
  set(EXTRA_INCLUDE_FLAG "")
  foreach(extra_path ${EXTRA_INCLUDE_DIRS})
    set(EXTRA_INCLUDE_FLAG "${EXTRA_INCLUDE_FLAG} -I ${extra_path}")
  endforeach()

  # cmake-format: off
  set(MAKE_DEFS
    [=[
      #
      # This file is autogenerated: PLEASE DO NOT EDIT IT.
      # CMake configure automatically generates the Make.defs template file.
      #

      TOPDIR := @NUTTX_DIR@
      APPDIR := @NUTTX_APPS_DIR@
      INCDIR := @CMAKE_BINARY_DIR@/bin/incdir
      MKDEP  := @CMAKE_BINARY_DIR@/bin/mkdeps
      EXTRAFLAGS := -I @CMAKE_BINARY_DIR@/include
      EXTRAFLAGS += @EXTRA_INCLUDE_FLAG@
      DEPCONFIG := @CMAKE_BINARY_DIR@/.config

      include @CMAKE_BINARY_DIR@/.config
      include $(TOPDIR)/tools/Config.mk

      # ARM specific
      ifeq ($(CONFIG_ARCH_ARM64),y)
      include $(TOPDIR)/arch/arm64/src/Toolchain.defs
      endif

      ifeq ($(CONFIG_ARCH_ARMV7A),y)
      include $(TOPDIR)/arch/arm/src/armv7-a/Toolchain.defs
      endif

      ifeq ($(CONFIG_ARCH_ARMV7M),y)
      include $(TOPDIR)/arch/arm/src/armv7-m/Toolchain.defs
      endif

      ifeq ($(CONFIG_ARCH_ARMV8M),y)
      include $(TOPDIR)/arch/arm/src/armv8-m/Toolchain.defs
      endif

      # SIM specific
      ifeq ($(CONFIG_ARCH_SIM),y)
      include $(TOPDIR)/boards/sim/sim/sim/scripts/Make.defs
      endif

      # RISCV specific
      ifeq ($(CONFIG_ARCH_RISCV),y)
      include $(TOPDIR)/arch/risc-v/src/common/Toolchain.defs
      endif

      # x86_64 specific
      ifeq ($(CONFIG_ARCH_X86_64),y)
      include $(TOPDIR)/arch/x86_64/src/intel64/Toolchain.defs
      endif

      # xtensa specific
      ifeq ($(CONFIG_ARCH_XTENSA),y)
      include $(TOPDIR)/arch/xtensa/src/lx7/Toolchain.defs
      endif

      CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe
      CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe
      CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS)
      AFLAGS := $(CFLAGS) -D__ASSEMBLY__

      include $(APPDIR)/Make.defs
    ]=])
  # cmake-format: on
  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/Make.defs.in ${MAKE_DEFS})
  configure_file(${CMAKE_CURRENT_BINARY_DIR}/Make.defs.in
                 ${CMAKE_CURRENT_BINARY_DIR}/Make.defs @ONLY)

endfunction()

include(nuttx_parse_function_args)

# ~~~
# nuttx_call_apps_makefile
#
# Description:
#   Use the NuttX original build system to generate static libraries independently
#
#   In this method, the initialized NuttX Make build environment is faked
#   using the common Make.defs settings and the binary output of CMake.
#
# Example:
#  nuttx_call_apps_makefile(
#    TARGET
#    ffmpeg
#    TARGET_BIN
#    libffmpeg.a)
# ~~~

function(nuttx_call_apps_makefile)

  # parse arguments into variables

  nuttx_parse_function_args(
    FUNC
    nuttx_call_apps_makefile
    ONE_VALUE
    TARGET
    TARGET_BIN
    REQUIRED
    TARGET
    TARGET_BIN
    ARGN
    ${ARGN})

  # gen common defs in function call binary dir
  generate_common_defs()

  # call external module for exter build
  ExternalProject_Add(
    ${TARGET}_out_tree
    SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
    BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}"
    CONFIGURE_COMMAND
      bash -c
      "make -C ${CMAKE_CURRENT_SOURCE_DIR} DST_PATH=${CMAKE_CURRENT_BINARY_DIR} context ${MAKE_PARALLELISM}"
    BUILD_COMMAND
      bash -c
      "make -C ${CMAKE_CURRENT_SOURCE_DIR} DST_PATH=${CMAKE_CURRENT_BINARY_DIR} depend ${MAKE_PARALLELISM}"
    INSTALL_COMMAND
      bash -c
      "make -C ${CMAKE_CURRENT_SOURCE_DIR} DST_PATH=${CMAKE_CURRENT_BINARY_DIR} all ${MAKE_PARALLELISM}"
    BUILD_ALWAYS TRUE
    DEPENDS mkdeps incdir)

  # imported target need a generate rule
  add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_BIN}
    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_BIN}
    COMMENT "Generating ${TARGET_BIN}"
    DEPENDS ${TARGET}_out_tree)

  # create a virtual intermediate dependency target
  add_custom_target(${TARGET}_bin ALL
                    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_BIN})

  # define IMPORTED target ant its relation chain
  add_library(${TARGET} STATIC IMPORTED GLOBAL)
  add_dependencies(${TARGET} ${TARGET}_bin)
  add_dependencies(nuttx ${TARGET})
  set_target_properties(
    ${TARGET} PROPERTIES IMPORTED_LOCATION
                         ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_BIN})
  set_property(GLOBAL APPEND PROPERTY NUTTX_SYSTEM_LIBRARIES ${TARGET})

endfunction()
